
#include "crtfileio.h"
#include <ddk.h>

static int s_offset = 0;

FILE* my_fopen(const char *filePath, const char* mode)
{
    ECode ec;
    IBasicFileSystem *pIBfs = NULL;
    IBasicFile *iSrcFile = NULL;
    IAbsoluteIO *iAbsoluteIO = NULL;
    IBasicDirectory *pDir = NULL;

    wchar_t pwszFullPath[_MAX_FNAME] = {0};
    WStringBuf_<_MAX_FNAME> wsbFileName;

    MbsToWcs(pwszFullPath, filePath, _MAX_FNAME);

    ec = DzFindService(L"ktfs", (PInterface *)&pIBfs);
    if (FAILED(ec)) {
//        kprintf("my_fopen:DzFindService ktfs.ec=%08x\n", ec);
        return NULL;
    }

    ec = pIBfs->GetRoot(&pDir);
    pIBfs->Release();
    if (FAILED(ec)) {
//        kprintf("my_fopen:pIBfs->GetRoot.ec=%08x\n", ec);
        return NULL;
    }

//    kprintf("Will Lookup:pwszFullPath=%S.%s\n", pwszFullPath, mode);
    if (!strcmp("rb", mode) || !strcmp("rb+", mode)) {
        ec = pDir->Lookup(pwszFullPath, &iSrcFile);
//        kprintf("Lookup result1:ec=%08x\n", ec);
        pDir->Release();
        if (FAILED(ec)) {
            return NULL;
        }

        if (!strcmp("rb+", mode)) {
            IAbsoluteIO::Probe(iSrcFile)->GetSize(&s_offset);
            ec = iSrcFile->SetAccessMode(FileAccessMode_ReadWrite);
//            kprintf("SetAccessMode1 result:ec=%08x\n", ec);
            if (FAILED(ec)) {
                iSrcFile->Release();
                return NULL;
            }
        } else {
            ec = iSrcFile->SetAccessMode(FileAccessMode_Read);
//            kprintf("SetAccessMode2 result:ec=%08x\n", ec);
            if (FAILED(ec)) {
                iSrcFile->Release();
                return NULL;
            }
        }
    } else {
        ec = pDir->Lookup(pwszFullPath, &iSrcFile);
//        kprintf("Lookup result2:ec=%08x\n", ec);
        if (FAILED(ec)) {
            ec = pDir->CreateFile(pwszFullPath, FileAccessMode_ReadWrite, TRUE, &iSrcFile);
//            kprintf("CreateFile result:ec=%08x\n", ec);
            pDir->Release();
            if (FAILED(ec) || iSrcFile == NULL) {
                return NULL;
            }
        } else {
            pDir->Release();
        }
    }

    iAbsoluteIO = IAbsoluteIO::Probe(iSrcFile);
//    kprintf("file open ok.0x%08x\n", iAbsoluteIO);
    return (FILE *)iAbsoluteIO;
}

int my_fwrite(const void* indata, int size, int count, FILE* pFile)
{
    assert(pFile != NULL);

    int nWritten;

    MemoryBuf pmd((Byte*)indata, count*size, count*size);

    ECode ec = ((IAbsoluteIO *)pFile)->Write(s_offset, pmd, &nWritten);
//    kprintf("ec = %08x.s_offset = %d.nWritten = %d\n", ec, s_offset, nWritten);
    if (FAILED(ec)) {
        return -1;
    }

    s_offset += nWritten;
    return nWritten;
}

int my_fread(void* outdata, int size, int count, FILE* pFile)
{
    assert(pFile != NULL);

    IAbsoluteIO *iAbsoluteIO = NULL;

    MemoryBuf pmd((Byte*)outdata, count*size, 0);
    iAbsoluteIO = (IAbsoluteIO *)pFile;

    ECode ec = iAbsoluteIO->Read(s_offset, size*count, &pmd);
//    kprintf("my_fread:ec = %08x, (toRead=%d)?=(used=%d)\n", ec, size*count, pmd.GetUsed());
    if (FAILED(ec)) {
        return -1;
    }

    return pmd.GetUsed();
}

int my_fclose(FILE *pFile)
{
    assert(pFile != NULL);

    ((IAbsoluteIO *)pFile)->Release();
//    kprintf("my_fclose\n");
    return 0;
}

int my_fseek(FILE *pFile, int offset, int seekType)
{
    s_offset = offset;
//    kprintf("my_fseek=%d\n", s_offset);
    return 0;
}

int my_fflush(FILE *pFile)
{
    assert(pFile != NULL);

    IBasicFile::Probe((IAbsoluteIO*)pFile)->Sync();
//    kprintf("my_fflush\n");
    return 0;
}

int my_ftell(FILE* pFile)
{
    int nSize = 0;

    assert(pFile != NULL);

    ECode ec = ((IAbsoluteIO *)pFile)->GetSize(&nSize);
    if (FAILED(ec)) {
        return -1;
    }

//    kprintf("my_ftell=%d\n", nSize);
    return nSize;
}
